/*
 *  Qucik Sort
 *
 *  Promotion tips:
 *  1. cutoff to insertion sort
 *  2. median-of-three
 *  3. three-ways partition
 */

package algs4.sort;

import java.util.Random;

public class Quick
{
    private static final int CUTOFF = 8;

    public static void sort(Comparable[] a) {
        sort(a, 0, a.length - 1);
    }

    public static void sort(Comparable[] a, int lo, int hi) {
        if (hi <= lo + CUTOFF) {
            insertionSort(a, lo, hi);
            return;
        }

        int mid = partition(a, lo, hi);
        sort(a, lo, mid - 1);
        sort(a, mid + 1, hi);
    }

    private static void insertionSort(Comparable[] a, int lo, int hi) {
        for (int i = lo + 1; i <= hi; i++) {
            int j;
            Comparable v = a[i];
            for (j = i; j > 0 && v.compareTo(a[j-1]) < 0; j--)
                a[j] = a[j-1];
            a[j] = v;
        }
    }

    private static int partition(Comparable[] a, int lo, int hi) {
        int i = lo, j = hi;
        Comparable pivot = a[lo];

        while (i < j) {
            while (i < j && pivot.compareTo(a[j]) <= 0) j--;
            a[i] = a[j];

            while (i < j && pivot.compareTo(a[i]) >= 0) i++;
            a[j] = a[i];
        }
        a[i] = pivot;

        return i;
    }

    private static void show(Comparable[] a) {
        for (Comparable i : a)
            System.out.print(i + " ");
        System.out.println();
    }

    public static void main(String[] args) {
        if (args.length != 1) {
            System.out.println("Usage: Command N");
            System.exit(1);
        }
        int n = Integer.parseInt(args[0]);;

        // Build random array of integer
        Integer[] a   = new Integer[n];
        Random random = new Random(System.currentTimeMillis());
        for (int i = 0; i < n; i++)
            a[i] = random.nextInt(n);

        System.out.print("BF: "); show(a);
        sort(a);
        System.out.print("AF: "); show(a);
    }
}
